/*
 * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

package com.sun.corba.se.impl.orbutil;

import java.lang.Character;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.rmi.NoSuchObjectException;
import java.security.AccessController;
import java.security.PermissionCollection;
import java.security.Policy;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
import java.util.Map.Entry;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Enumeration;
import java.util.Properties;
import java.util.IdentityHashMap;
import java.util.StringTokenizer;
import java.util.NoSuchElementException;

import javax.rmi.CORBA.ValueHandler;
import javax.rmi.CORBA.ValueHandlerMultiFormat;
import javax.rmi.CORBA.Util;

import org.omg.CORBA.StructMember;
import org.omg.CORBA.TypeCode;
import org.omg.CORBA.Any;
import org.omg.CORBA.TCKind;
import org.omg.CORBA.SystemException;
import org.omg.CORBA.CompletionStatus;
import org.omg.CORBA.DATA_CONVERSION;
import org.omg.CORBA.BAD_PARAM;
import org.omg.CORBA.BAD_OPERATION;
import org.omg.CORBA.INTERNAL;
import org.omg.CORBA.TypeCodePackage.BadKind;
import org.omg.CORBA.portable.OutputStream;
import org.omg.CORBA.portable.InputStream;

import com.sun.corba.se.pept.transport.ContactInfoList;

import com.sun.corba.se.spi.ior.IOR;
import com.sun.corba.se.spi.presentation.rmi.StubAdapter;
import com.sun.corba.se.spi.orb.ORB;
import com.sun.corba.se.spi.orb.ORBVersion;
import com.sun.corba.se.spi.orb.ORBVersionFactory;
import com.sun.corba.se.spi.protocol.CorbaClientDelegate;
import com.sun.corba.se.spi.protocol.CorbaMessageMediator;
import com.sun.corba.se.spi.transport.CorbaContactInfoList;
import com.sun.corba.se.spi.logging.CORBALogDomains;
import com.sun.corba.se.spi.ior.iiop.IIOPProfile;
import com.sun.corba.se.spi.ior.iiop.IIOPProfileTemplate;

import com.sun.corba.se.impl.protocol.giopmsgheaders.Message;
import com.sun.corba.se.impl.corba.CORBAObjectImpl;
import com.sun.corba.se.impl.logging.ORBUtilSystemException;
import com.sun.corba.se.impl.logging.OMGSystemException;
import com.sun.corba.se.impl.ior.iiop.JavaSerializationComponent;

import sun.corba.SharedSecrets;

/**
 * Handy class full of static functions that don't belong in util.Utility for pure ORB reasons.
 */
public final class ORBUtility {

  private ORBUtility() {
  }

  private static ORBUtilSystemException wrapper = ORBUtilSystemException.get(
      CORBALogDomains.UTIL);
  private static OMGSystemException omgWrapper = OMGSystemException.get(
      CORBALogDomains.UTIL);

  private static StructMember[] members = null;

  private static StructMember[] systemExceptionMembers(ORB orb) {
    if (members == null) {
      members = new StructMember[3];
      members[0] = new StructMember("id", orb.create_string_tc(0), null);
      members[1] = new StructMember("minor", orb.get_primitive_tc(TCKind.tk_long), null);
      members[2] = new StructMember("completed", orb.get_primitive_tc(TCKind.tk_long), null);
    }
    return members;
  }

  private static TypeCode getSystemExceptionTypeCode(ORB orb, String repID, String name) {
    synchronized (TypeCode.class) {
      return orb.create_exception_tc(repID, name, systemExceptionMembers(orb));
    }
  }

  private static boolean isSystemExceptionTypeCode(TypeCode type, ORB orb) {
    StructMember[] systemExceptionMembers = systemExceptionMembers(orb);
    try {
      return (type.kind().value() == TCKind._tk_except &&
          type.member_count() == 3 &&
          type.member_type(0).equal(systemExceptionMembers[0].type) &&
          type.member_type(1).equal(systemExceptionMembers[1].type) &&
          type.member_type(2).equal(systemExceptionMembers[2].type));
    } catch (BadKind ex) {
      return false;
    } catch (org.omg.CORBA.TypeCodePackage.Bounds ex) {
      return false;
    }
  }

  /**
   * Static method for writing a CORBA standard exception to an Any.
   *
   * @param any The Any to write the SystemException into.
   */
  public static void insertSystemException(SystemException ex, Any any) {
    OutputStream out = any.create_output_stream();
    ORB orb = (ORB) (out.orb());
    String name = ex.getClass().getName();
    String repID = ORBUtility.repositoryIdOf(name);
    out.write_string(repID);
    out.write_long(ex.minor);
    out.write_long(ex.completed.value());
    any.read_value(out.create_input_stream(),
        getSystemExceptionTypeCode(orb, repID, name));
  }

  public static SystemException extractSystemException(Any any) {
    InputStream in = any.create_input_stream();
    ORB orb = (ORB) (in.orb());
    if (!isSystemExceptionTypeCode(any.type(), orb)) {
      throw wrapper.unknownDsiSysex(CompletionStatus.COMPLETED_MAYBE);
    }
    return ORBUtility.readSystemException(in);
  }

  /**
   * Return default ValueHandler
   */
  public static ValueHandler createValueHandler() {
    return Util.createValueHandler();
  }

  /**
   * Returns true if it was accurately determined that the remote ORB is
   * a foreign (non-JavaSoft) ORB.  Note:  If passed the ORBSingleton, this
   * will return false.
   */
  public static boolean isForeignORB(ORB orb) {
    if (orb == null) {
      return false;
    }

    try {
      return orb.getORBVersion().equals(ORBVersionFactory.getFOREIGN());
    } catch (SecurityException se) {
      return false;
    }
  }

  /**
   * Unmarshal a byte array to an integer.
   * Assume the bytes are in BIGENDIAN order.
   * i.e. array[offset] is the most-significant-byte
   * and  array[offset+3] is the least-significant-byte.
   *
   * @param array The array of bytes.
   * @param offset The offset from which to start unmarshalling.
   */
  public static int bytesToInt(byte[] array, int offset) {
    int b1, b2, b3, b4;

    b1 = (array[offset++] << 24) & 0xFF000000;
    b2 = (array[offset++] << 16) & 0x00FF0000;
    b3 = (array[offset++] << 8) & 0x0000FF00;
    b4 = (array[offset++] << 0) & 0x000000FF;

    return (b1 | b2 | b3 | b4);
  }

  /**
   * Marshal an integer to a byte array.
   * The bytes are in BIGENDIAN order.
   * i.e. array[offset] is the most-significant-byte
   * and  array[offset+3] is the least-significant-byte.
   *
   * @param array The array of bytes.
   * @param offset The offset from which to start marshalling.
   */
  public static void intToBytes(int value, byte[] array, int offset) {
    array[offset++] = (byte) ((value >>> 24) & 0xFF);
    array[offset++] = (byte) ((value >>> 16) & 0xFF);
    array[offset++] = (byte) ((value >>> 8) & 0xFF);
    array[offset++] = (byte) ((value >>> 0) & 0xFF);
  }

  /**
   * Converts an Ascii Character into Hexadecimal digit
   */
  public static int hexOf(char x) {
    int val;

    val = x - '0';
    if (val >= 0 && val <= 9) {
      return val;
    }

    val = (x - 'a') + 10;
    if (val >= 10 && val <= 15) {
      return val;
    }

    val = (x - 'A') + 10;
    if (val >= 10 && val <= 15) {
      return val;
    }

    throw wrapper.badHexDigit();
  }

  // method moved from util.Utility

  /**
   * Static method for writing a CORBA standard exception to a stream.
   *
   * @param strm The OutputStream to use for marshaling.
   */
  public static void writeSystemException(SystemException ex, OutputStream strm) {
    String s;

    s = repositoryIdOf(ex.getClass().getName());
    strm.write_string(s);
    strm.write_long(ex.minor);
    strm.write_long(ex.completed.value());
  }

  /**
   * Static method for reading a CORBA standard exception from a stream.
   *
   * @param strm The InputStream to use for unmarshaling.
   */
  public static SystemException readSystemException(InputStream strm) {
    try {
      String name = classNameOf(strm.read_string());
      SystemException ex = (SystemException) SharedSecrets.
          getJavaCorbaAccess().loadClass(name).newInstance();
      ex.minor = strm.read_long();
      ex.completed = CompletionStatus.from_int(strm.read_long());
      return ex;
    } catch (Exception ex) {
      throw wrapper.unknownSysex(CompletionStatus.COMPLETED_MAYBE, ex);
    }
  }

  /**
   * Get the class name corresponding to a particular repository Id.
   * This is used by the system to unmarshal (instantiate) the
   * appropriate exception class for an marshaled as the value of
   * its repository Id.
   *
   * @param repositoryId The repository Id for which we want a class name.
   */
  public static String classNameOf(String repositoryId) {
    String className = null;

    className = (String) exceptionClassNames.get(repositoryId);
    if (className == null) {
      className = "org.omg.CORBA.UNKNOWN";
    }

    return className;
  }

  /**
   * Return true if this repositoryId is a SystemException.
   *
   * @param repositoryId The repository Id to check.
   */
  public static boolean isSystemException(String repositoryId) {
    String className = null;

    className = (String) exceptionClassNames.get(repositoryId);
    if (className == null) {
      return false;
    } else {
      return true;
    }
  }

  /**
   * @return the Java serialization encoding version.
   */
  public static byte getEncodingVersion(ORB orb, IOR ior) {

    // Is Java serialization enabled?
    // Check the JavaSerializationComponent (tagged component)
    // in the IIOPProfile. If present, the peer ORB's GIOP is capable
    // of using Java serialization instead of CDR serialization.
    // In such a case, use Java serialization, iff the java serialization
    // versions match.

    if (orb.getORBData().isJavaSerializationEnabled()) {
      IIOPProfile prof = ior.getProfile();
      IIOPProfileTemplate profTemp =
          (IIOPProfileTemplate) prof.getTaggedProfileTemplate();
      java.util.Iterator iter = profTemp.iteratorById(
          ORBConstants.TAG_JAVA_SERIALIZATION_ID);
      if (iter.hasNext()) {
        JavaSerializationComponent jc =
            (JavaSerializationComponent) iter.next();
        byte jcVersion = jc.javaSerializationVersion();
        if (jcVersion >= Message.JAVA_ENC_VERSION) {
          return Message.JAVA_ENC_VERSION;
        } else if (jcVersion > Message.CDR_ENC_VERSION) {
          return jc.javaSerializationVersion();
        } else {
          // throw error?
          // Since encodingVersion is <= 0 (CDR_ENC_VERSION).
        }
      }
    }
    return Message.CDR_ENC_VERSION; // default
  }

  /**
   * Get the repository id corresponding to a particular class.
   * This is used by the system to write the
   * appropriate repository id for a system exception.
   *
   * @param name The class name of the system exception.
   */
  public static String repositoryIdOf(String name) {
    String id;

    id = (String) exceptionRepositoryIds.get(name);
    if (id == null) {
      id = "IDL:omg.org/CORBA/UNKNOWN:1.0";
    }

    return id;
  }

  private static final Hashtable exceptionClassNames = new Hashtable();
  private static final Hashtable exceptionRepositoryIds = new Hashtable();

  static {

    //
    // construct repositoryId -> className hashtable
    //
    exceptionClassNames.put("IDL:omg.org/CORBA/BAD_CONTEXT:1.0",
        "org.omg.CORBA.BAD_CONTEXT");
    exceptionClassNames.put("IDL:omg.org/CORBA/BAD_INV_ORDER:1.0",
        "org.omg.CORBA.BAD_INV_ORDER");
    exceptionClassNames.put("IDL:omg.org/CORBA/BAD_OPERATION:1.0",
        "org.omg.CORBA.BAD_OPERATION");
    exceptionClassNames.put("IDL:omg.org/CORBA/BAD_PARAM:1.0",
        "org.omg.CORBA.BAD_PARAM");
    exceptionClassNames.put("IDL:omg.org/CORBA/BAD_TYPECODE:1.0",
        "org.omg.CORBA.BAD_TYPECODE");
    exceptionClassNames.put("IDL:omg.org/CORBA/COMM_FAILURE:1.0",
        "org.omg.CORBA.COMM_FAILURE");
    exceptionClassNames.put("IDL:omg.org/CORBA/DATA_CONVERSION:1.0",
        "org.omg.CORBA.DATA_CONVERSION");
    exceptionClassNames.put("IDL:omg.org/CORBA/IMP_LIMIT:1.0",
        "org.omg.CORBA.IMP_LIMIT");
    exceptionClassNames.put("IDL:omg.org/CORBA/INTF_REPOS:1.0",
        "org.omg.CORBA.INTF_REPOS");
    exceptionClassNames.put("IDL:omg.org/CORBA/INTERNAL:1.0",
        "org.omg.CORBA.INTERNAL");
    exceptionClassNames.put("IDL:omg.org/CORBA/INV_FLAG:1.0",
        "org.omg.CORBA.INV_FLAG");
    exceptionClassNames.put("IDL:omg.org/CORBA/INV_IDENT:1.0",
        "org.omg.CORBA.INV_IDENT");
    exceptionClassNames.put("IDL:omg.org/CORBA/INV_OBJREF:1.0",
        "org.omg.CORBA.INV_OBJREF");
    exceptionClassNames.put("IDL:omg.org/CORBA/MARSHAL:1.0",
        "org.omg.CORBA.MARSHAL");
    exceptionClassNames.put("IDL:omg.org/CORBA/NO_MEMORY:1.0",
        "org.omg.CORBA.NO_MEMORY");
    exceptionClassNames.put("IDL:omg.org/CORBA/FREE_MEM:1.0",
        "org.omg.CORBA.FREE_MEM");
    exceptionClassNames.put("IDL:omg.org/CORBA/NO_IMPLEMENT:1.0",
        "org.omg.CORBA.NO_IMPLEMENT");
    exceptionClassNames.put("IDL:omg.org/CORBA/NO_PERMISSION:1.0",
        "org.omg.CORBA.NO_PERMISSION");
    exceptionClassNames.put("IDL:omg.org/CORBA/NO_RESOURCES:1.0",
        "org.omg.CORBA.NO_RESOURCES");
    exceptionClassNames.put("IDL:omg.org/CORBA/NO_RESPONSE:1.0",
        "org.omg.CORBA.NO_RESPONSE");
    exceptionClassNames.put("IDL:omg.org/CORBA/OBJ_ADAPTER:1.0",
        "org.omg.CORBA.OBJ_ADAPTER");
    exceptionClassNames.put("IDL:omg.org/CORBA/INITIALIZE:1.0",
        "org.omg.CORBA.INITIALIZE");
    exceptionClassNames.put("IDL:omg.org/CORBA/PERSIST_STORE:1.0",
        "org.omg.CORBA.PERSIST_STORE");
    exceptionClassNames.put("IDL:omg.org/CORBA/TRANSIENT:1.0",
        "org.omg.CORBA.TRANSIENT");
    exceptionClassNames.put("IDL:omg.org/CORBA/UNKNOWN:1.0",
        "org.omg.CORBA.UNKNOWN");
    exceptionClassNames.put("IDL:omg.org/CORBA/OBJECT_NOT_EXIST:1.0",
        "org.omg.CORBA.OBJECT_NOT_EXIST");

    // SystemExceptions from OMG Transactions Service Spec
    exceptionClassNames.put("IDL:omg.org/CORBA/INVALID_TRANSACTION:1.0",
        "org.omg.CORBA.INVALID_TRANSACTION");
    exceptionClassNames.put("IDL:omg.org/CORBA/TRANSACTION_REQUIRED:1.0",
        "org.omg.CORBA.TRANSACTION_REQUIRED");
    exceptionClassNames.put("IDL:omg.org/CORBA/TRANSACTION_ROLLEDBACK:1.0",
        "org.omg.CORBA.TRANSACTION_ROLLEDBACK");

    // from portability RTF 98-07-01.txt
    exceptionClassNames.put("IDL:omg.org/CORBA/INV_POLICY:1.0",
        "org.omg.CORBA.INV_POLICY");

    // from orbrev/00-09-01 (CORBA 2.4 Draft Specification)
    exceptionClassNames.
        put("IDL:omg.org/CORBA/TRANSACTION_UNAVAILABLE:1.0",
            "org.omg.CORBA.TRANSACTION_UNAVAILABLE");
    exceptionClassNames.put("IDL:omg.org/CORBA/TRANSACTION_MODE:1.0",
        "org.omg.CORBA.TRANSACTION_MODE");

    // Exception types introduced between CORBA 2.4 and 3.0
    exceptionClassNames.put("IDL:omg.org/CORBA/CODESET_INCOMPATIBLE:1.0",
        "org.omg.CORBA.CODESET_INCOMPATIBLE");
    exceptionClassNames.put("IDL:omg.org/CORBA/REBIND:1.0",
        "org.omg.CORBA.REBIND");
    exceptionClassNames.put("IDL:omg.org/CORBA/TIMEOUT:1.0",
        "org.omg.CORBA.TIMEOUT");
    exceptionClassNames.put("IDL:omg.org/CORBA/BAD_QOS:1.0",
        "org.omg.CORBA.BAD_QOS");

    // Exception types introduced in CORBA 3.0
    exceptionClassNames.put("IDL:omg.org/CORBA/INVALID_ACTIVITY:1.0",
        "org.omg.CORBA.INVALID_ACTIVITY");
    exceptionClassNames.put("IDL:omg.org/CORBA/ACTIVITY_COMPLETED:1.0",
        "org.omg.CORBA.ACTIVITY_COMPLETED");
    exceptionClassNames.put("IDL:omg.org/CORBA/ACTIVITY_REQUIRED:1.0",
        "org.omg.CORBA.ACTIVITY_REQUIRED");

    //
    // construct className -> repositoryId hashtable
    //
    Enumeration keys = exceptionClassNames.keys();
    java.lang.Object s;
    String rId;
    String cName;

    try {
      while (keys.hasMoreElements()) {
        s = keys.nextElement();
        rId = (String) s;
        cName = (String) exceptionClassNames.get(rId);
        exceptionRepositoryIds.put(cName, rId);
      }
    } catch (NoSuchElementException e) {
    }
  }

  /**
   * Parse a version string such as "1.1.6" or "jdk1.2fcs" into
   * a version array of integers {1, 1, 6} or {1, 2}.
   * A string of "n." or "n..m" is equivalent to "n.0" or "n.0.m" respectively.
   */
  public static int[] parseVersion(String version) {
    if (version == null) {
      return new int[0];
    }
    char[] s = version.toCharArray();
    //find the maximum span of the string "n.n.n..." where n is an integer
    int start = 0;
    for (; start < s.length && (s[start] < '0' || s[start] > '9'); ++start) {
      if (start == s.length)      //no digit found
      {
        return new int[0];
      }
    }
    int end = start + 1;
    int size = 1;
    for (; end < s.length; ++end) {
      if (s[end] == '.') {
        ++size;
      } else if (s[end] < '0' || s[end] > '9') {
        break;
      }
    }
    int[] val = new int[size];
    for (int i = 0; i < size; ++i) {
      int dot = version.indexOf('.', start);
      if (dot == -1 || dot > end) {
        dot = end;
      }
      if (start >= dot)   //cases like "n." or "n..m"
      {
        val[i] = 0;     //convert equivalent to "n.0" or "n.0.m"
      } else {
        val[i] = Integer.parseInt(version.substring(start, dot));
      }
      start = dot + 1;
    }
    return val;
  }

  /**
   * Compare two version arrays.
   * Return 1, 0 or -1 if v1 is greater than, equal to, or less than v2.
   */
  public static int compareVersion(int[] v1, int[] v2) {
    if (v1 == null) {
      v1 = new int[0];
    }
    if (v2 == null) {
      v2 = new int[0];
    }
    for (int i = 0; i < v1.length; ++i) {
      if (i >= v2.length || v1[i] > v2[i])        //v1 is longer or greater than v2
      {
        return 1;
      }
      if (v1[i] < v2[i]) {
        return -1;
      }
    }
    return v1.length == v2.length ? 0 : -1;
  }

  /**
   * Compare two version strings.
   * Return 1, 0 or -1 if v1 is greater than, equal to, or less than v2.
   */
  public static synchronized int compareVersion(String v1, String v2) {
    return compareVersion(parseVersion(v1), parseVersion(v2));
  }

  private static String compressClassName(String name) {
    // Note that this must end in . in order to be renamed correctly.
    String prefix = "com.sun.corba.se.";
    if (name.startsWith(prefix)) {
      return "(ORB)." + name.substring(prefix.length());
    } else {
      return name;
    }
  }

  // Return a compressed representation of the thread name.  This is particularly
  // useful on the server side, where there are many SelectReaderThreads, and
  // we need a short unambiguous name for such threads.
  public static String getThreadName(Thread thr) {
    if (thr == null) {
      return "null";
    }

    // This depends on the formatting in SelectReaderThread and CorbaConnectionImpl.
    // Pattern for SelectReaderThreads:
    // SelectReaderThread CorbaConnectionImpl[ <host> <post> <state>]
    // Any other pattern in the Thread's name is just returned.
    String name = thr.getName();
    StringTokenizer st = new StringTokenizer(name);
    int numTokens = st.countTokens();
    if (numTokens != 5) {
      return name;
    }

    String[] tokens = new String[numTokens];
    for (int ctr = 0; ctr < numTokens; ctr++) {
      tokens[ctr] = st.nextToken();
    }

    if (!tokens[0].equals("SelectReaderThread")) {
      return name;
    }

    return "SelectReaderThread[" + tokens[2] + ":" + tokens[3] + "]";
  }

  private static String formatStackTraceElement(StackTraceElement ste) {
    return compressClassName(ste.getClassName()) + "." + ste.getMethodName() +
        (ste.isNativeMethod() ? "(Native Method)" :
            (ste.getFileName() != null && ste.getLineNumber() >= 0 ?
                "(" + ste.getFileName() + ":" + ste.getLineNumber() + ")" :
                (ste.getFileName() != null ? "(" + ste.getFileName() + ")" : "(Unknown Source)")));
  }

  private static void printStackTrace(StackTraceElement[] trace) {
    System.out.println("    Stack Trace:");
    // print the stack trace, ommitting the zeroth element, which is
    // always this method.
    for (int ctr = 1; ctr < trace.length; ctr++) {
      System.out.print("        >");
      System.out.println(formatStackTraceElement(trace[ctr]));
    }
  }

  //
  // Implements all dprint calls in this package.
  //
  public static synchronized void dprint(java.lang.Object obj, String msg) {
    System.out.println(
        compressClassName(obj.getClass().getName()) + "(" +
            getThreadName(Thread.currentThread()) + "): " + msg);
  }

  public static synchronized void dprint(String className, String msg) {
    System.out.println(
        compressClassName(className) + "(" +
            getThreadName(Thread.currentThread()) + "): " + msg);
  }

  public synchronized void dprint(String msg) {
    ORBUtility.dprint(this, msg);
  }

  public static synchronized void dprintTrace(Object obj, String msg) {
    ORBUtility.dprint(obj, msg);

    Throwable thr = new Throwable();
    printStackTrace(thr.getStackTrace());
  }

  public static synchronized void dprint(java.lang.Object caller,
      String msg, Throwable t) {
    System.out.println(
        compressClassName(caller.getClass().getName()) +
            '(' + Thread.currentThread() + "): " + msg);

    if (t != null) {
      printStackTrace(t.getStackTrace());
    }
  }

  public static String[] concatenateStringArrays(String[] arr1, String[] arr2) {
    String[] result = new String[
        arr1.length + arr2.length];

    for (int ctr = 0; ctr < arr1.length; ctr++) {
      result[ctr] = arr1[ctr];
    }

    for (int ctr = 0; ctr < arr2.length; ctr++) {
      result[ctr + arr1.length] = arr2[ctr];
    }

    return result;
  }

  /**
   * Throws the CORBA equivalent of a java.io.NotSerializableException
   *
   * Duplicated from util/Utility for Pure ORB reasons.  There are two
   * reasons for this:
   *
   * 1) We can't introduce dependencies on the util version from outside
   * of the io/util packages since it will not exist in the pure ORB
   * build running on JDK 1.3.x.
   *
   * 2) We need to pick up the correct minor code from OMGSystemException.
   */
  public static void throwNotSerializableForCorba(String className) {
    throw omgWrapper.notSerializable(CompletionStatus.COMPLETED_MAYBE,
        className);
  }

  /**
   * Returns the maximum stream format version supported by our
   * ValueHandler.
   */
  public static byte getMaxStreamFormatVersion() {
    ValueHandler vh = Util.createValueHandler();

    if (!(vh instanceof javax.rmi.CORBA.ValueHandlerMultiFormat)) {
      return ORBConstants.STREAM_FORMAT_VERSION_1;
    } else {
      return ((ValueHandlerMultiFormat) vh).getMaximumStreamFormatVersion();
    }
  }

  public static CorbaClientDelegate makeClientDelegate(IOR ior) {
    ORB orb = ior.getORB();
    CorbaContactInfoList ccil = orb.getCorbaContactInfoListFactory().create(ior);
    CorbaClientDelegate del = orb.getClientDelegateFactory().create(ccil);
    return del;
  }

  /**
   * This method is used to create untyped object references.
   */
  public static org.omg.CORBA.Object makeObjectReference(IOR ior) {
    CorbaClientDelegate del = makeClientDelegate(ior);
    org.omg.CORBA.Object objectImpl = new CORBAObjectImpl();
    StubAdapter.setDelegate(objectImpl, del);
    return objectImpl;
  }

  /**
   * This method obtains an IOR from a CORBA object reference.
   * It will return null if obj is a local object, a null object,
   * or an object implemented by a different ORB.  It will
   * throw BAD_OPERATION if obj is an unconnected RMI-IIOP object.
   *
   * @return IOR the IOR that represents this objref.  This will never be null.
   * @throws BAD_OPERATION (from oi._get_delegate) if obj is a normal objref, but does not have a
   * delegate set.
   * @throws BAD_PARAM if obj is a local object, or else was created by a foreign ORB.
   */
  public static IOR getIOR(org.omg.CORBA.Object obj) {
    if (obj == null) {
      throw wrapper.nullObjectReference();
    }

    IOR ior = null;
    if (StubAdapter.isStub(obj)) {
      org.omg.CORBA.portable.Delegate del = StubAdapter.getDelegate(
          obj);

      if (del instanceof CorbaClientDelegate) {
        CorbaClientDelegate cdel = (CorbaClientDelegate) del;
        ContactInfoList cil = cdel.getContactInfoList();

        if (cil instanceof CorbaContactInfoList) {
          CorbaContactInfoList ccil = (CorbaContactInfoList) cil;
          ior = ccil.getTargetIOR();
          if (ior == null) {
            throw wrapper.nullIor();
          }

          return ior;
        } else {
          // This is our code, but the ContactInfoList is not a
          // CorbaContactInfoList.  This should not happen, because
          // we are in the CORBA application of the DCSA framework.
          // This is a coding error, and thus an INTERNAL exception
          // should be thrown.
          // XXX needs minor code
          throw new INTERNAL();
        }
      }

      // obj is implemented by a foreign ORB, because the Delegate is not a
      // ClientDelegate.
      // XXX this case could be handled by marshalling and
      // unmarshalling.  However, object_to_string cannot be used
      // here, as it is implemented with getIOR.  Note that this
      // will require access to an ORB, so that we can create streams
      // as needed.  The ORB is available simply as io._orb().
      throw wrapper.objrefFromForeignOrb();
    } else {
      throw wrapper.localObjectNotAllowed();
    }
  }

  /**
   * Obtains an IOR for the object reference obj, first connecting it to
   * the ORB if necessary.
   *
   * @return IOR the IOR that represents this objref.  This will never be null.
   * @throws BAD_OPERATION if the object could not be connected, if a connection attempt was
   * needed.
   * @throws BAD_PARAM if obj is a local object, or else was created by a foreign ORB.
   */
  public static IOR connectAndGetIOR(ORB orb, org.omg.CORBA.Object obj) {
    IOR result;
    try {
      result = getIOR(obj);
    } catch (BAD_OPERATION bop) {
      if (StubAdapter.isStub(obj)) {
        try {
          StubAdapter.connect(obj, orb);
        } catch (java.rmi.RemoteException exc) {
          throw wrapper.connectingServant(exc);
        }
      } else {
        orb.connect(obj);
      }

      result = getIOR(obj);
    }

    return result;
  }

  public static String operationNameAndRequestId(CorbaMessageMediator m) {
    return "op/" + m.getOperationName() + " id/" + m.getRequestId();
  }

  public static boolean isPrintable(char c) {
    if (Character.isJavaIdentifierStart(c)) {
      // Letters and $ _
      return true;
    }
    if (Character.isDigit(c)) {
      return true;
    }
    switch (Character.getType(c)) {
      case Character.MODIFIER_SYMBOL:
        return true; // ` ^
      case Character.DASH_PUNCTUATION:
        return true; // -
      case Character.MATH_SYMBOL:
        return true; // = ~ + | < >
      case Character.OTHER_PUNCTUATION:
        return true; // !@#%&*;':",./?
      case Character.START_PUNCTUATION:
        return true; // ( [ {
      case Character.END_PUNCTUATION:
        return true; // ) ] }
    }
    return false;
  }

  public static String getClassSecurityInfo(final Class cl) {
    // Returns a String which looks similar to:
    // PermissionCollection java.security.Permissions@1053693 ...
    // (java.io.FilePermission <<ALL FILES>> ....)
    // (java.io.FilePermission /export0/sunwappserv/lib/- ...)
    // ... other permissions ...
    // Domain ProtectionDomain  (file:/export0/sunwappserv/lib-)
    // java.security.Permissions@141fedb (
    // (java.io.FilePermission <<ALL FILES>> ...)
    // (java.io.FilePermission /var/tmp//- ...)

    String result =
        (String) AccessController.doPrivileged(new PrivilegedAction() {
          public java.lang.Object run() {
            StringBuffer sb = new StringBuffer(500);
            ProtectionDomain pd = cl.getProtectionDomain();
            Policy policy = Policy.getPolicy();
            PermissionCollection pc = policy.getPermissions(pd);
            sb.append("\nPermissionCollection ");
            sb.append(pc.toString());
            // Don't need to add 'Protection Domain' string, it's
            // in ProtectionDomain.toString() already.
            sb.append(pd.toString());
            return sb.toString();
          }
        });
    return result;
  }
}

// End of file.
